package tk.pak0.audiomidifier.model.runnable;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

//import javax.sound.midi.ShortMessage;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.TargetDataLine;

import org.apache.log4j.Logger;

import tk.pak0.audiomidifier.controller.Controller;
import tk.pak0.audiomidifier.model.audio.pitchdet.A_PitchDetector;
import tk.pak0.audiomidifier.model.audio.pitchdet.ZeroCrossing;
//import tk.pak0.audiomidifier.model.midi.Note;
import tk.pak0.audiomidifier.model.persistence.A_DataHolder;
import tk.pak0.audiomidifier.model.persistence.XmlDataHolder;

public class PitchProcessor extends Thread {
	
	private Logger log = Logger.getLogger(MidiListener.class); 
	private volatile boolean run=false;
	// tamaño arbitrario
	private BlockingQueue<byte[]> chunkQueue = new ArrayBlockingQueue<byte[]>(10);
	
	private MidiListener midiThread;
	private A_PitchDetector pitchDetector;
	private Controller mainControl = Controller.getInstance();
	
	public void setMidiThread(MidiListener instance){
		this.midiThread = instance;
	}

	public void run() {
		run = true;
		
//		TargetDataLine inLine = (TargetDataLine) mainControl.getLineaEntradaSel();
//		AudioFormat format = inLine.getFormat();
		A_DataHolder dataHolder = XmlDataHolder.getInstance();
		// metemos el método de detección, hardcodeado por ahora
		pitchDetector = new ZeroCrossing(mainControl.getSampleRates()[dataHolder.sampleRate], dataHolder.smooth);
//		Controller mainControl = Controller.getInstance();
		
		while(run){
			log.trace("Run is "+run);
			try {
				// cargar frame
				log.debug("Cargar frame");
				byte[] chunk = chunkQueue.take();
				log.trace("Tamaño de frame de bytes"+chunk.length);
				short[] shortChunk = new short[chunk.length /2];
				log.trace("Tamaño de frame de shorts"+shortChunk.length);
				byte msb = 0;
				// procesar frame
				log.debug("Procesar frame");
				int zeroValues = 0;
				int nonZeroValues = 0;
				for(int j=0; j < chunk.length; j++){
					if(j % 2 == 1){
						ByteBuffer byteBuffer = ByteBuffer.allocate(2);
						byteBuffer.order(ByteOrder.BIG_ENDIAN);
						byteBuffer.put(msb);
						byteBuffer.put(chunk[j]);
						short shortVal = byteBuffer.getShort(0);
						shortChunk[(j-1)/2] = shortVal;
//						log.trace("Value: "+shortVal);
						if(shortVal == 0)
							zeroValues++;
						else
							nonZeroValues++;
					}else{
						msb = chunk[j];
					}
				}
				log.debug("Valores no ceros "+nonZeroValues);
				log.debug("Valores si ceros "+zeroValues);
				double f0 = pitchDetector.getPitch(shortChunk);
				log.debug("Frecuencia fundamental f0 "+f0);
//				long timestamp = System.currentTimeMillis();
//				Note nota = mainControl.midiTools.freqToNota(f0,(byte)0x7F);
//				nota.timeStamp = timestamp;
//				ShortMessage shortMessage = mainControl.midiTools.creaMensajeMidi(true, nota);
				
			} catch (InterruptedException e) {
				log.error("Interrupted exception", e);
				e.printStackTrace();
			} catch (LineUnavailableException e){
				log.error("Linea no disponible", e);
				e.printStackTrace();
			}
//			// crear nota
//			log.debug("Crear nota");
//			// enviar nota
//			log.debug("Enviar nota");
		}
		log.trace("Ha terminado el hilo y run es"+run);
	}
	
	public void putChunkInQueue(byte[] chunk) throws InterruptedException{
		if(run){
			this.chunkQueue.put(chunk);
		}
	}
	
	public void kill(){
		this.run = false;
	}
}
